from flask_restplus import Resource, Namespace, fields, marshal, reqparse
from common.decorators import catch_error
from app.user.decorators import token_required
from common.responses import ok
from common import constant
from app.order.purchase.controller import purchase_order_sku_model, \
    purchase_order_model_for_list
from app.file.controller import file_model
from app.file.service import get_img_files_from_belong
from common.utils import get_default_date
from common.request_parser import get_parser
from app.order.transfer import dao
from app.order.transfer.model import TransferOrder, TransferOrderSku
from app.file.model import FileRelation, File
from exts import db
from flask_restplus import Model
from app.product.sku.controller import sku_model
from app.product.unit.controller import unit_model
from app.storage.warehouse.controller import warehouse_model
from app.storage.storage_record.model import StorageRecord

api = Namespace('transfer_order')


def get_sku_storage_num(sku_id, warehouse_id):
    storage_record = StorageRecord.query.filter_by(sku_id=sku_id, warehouse_id=warehouse_id).first()
    return storage_record.num if storage_record else 0


def get_sku_storage_cost_price(sku_id, warehouse_id):
    storage_record = StorageRecord.query.filter_by(sku_id=sku_id, warehouse_id=warehouse_id).first()
    return storage_record.cost_price if storage_record else 0


# ---------- model ----------
transfer_order_sku_model = Model('transfer_order_sku_model', {
    'id': fields.Integer(description='编号'),
    "sku_id": fields.Integer(),
    'sku': fields.Nested(sku_model),
    'unit_id': fields.Integer(),
    'unit': fields.Nested(unit_model),
    "num": fields.Float(),
    "from_before_num": fields.Float(),
    "to_before_num": fields.Float(),
    # # # 当前实时库存 todo 从库存表中获取
    # "current_num": fields.Float(),
    "cost_price": fields.Float(),
})
transfer_order_model_for_list = Model('transfer_order_model_for_list', {
    'id': fields.Integer(description='编号'),
    'order_sn': fields.String(description='单据编号'),
    'status': fields.String(description='状态'),
    'draft_status': fields.String(description='草稿状态'),
    'date': fields.Date(description='日期'),

    'notes': fields.String(description='备注'),
    "create_datetime": fields.DateTime(description='创建时间'),
    "update_datetime": fields.DateTime(description='更新时间'),

    "from_warehouse_id": fields.Integer(),
    "from_warehouse": fields.Nested(warehouse_model),

    "to_warehouse_id": fields.Integer(),
    "to_warehouse": fields.Nested(warehouse_model),
})

transfer_order_model_for_detail = transfer_order_model_for_list.inherit('transfer_order_model_for_detail', {
    "order_skus": fields.Nested(transfer_order_sku_model),
    # 图片
    'images': fields.List(fields.Nested(file_model),
                          attribute=lambda transfer_order: get_img_files_from_belong(
                              transfer_order.id, constant.FileBelongType.TRANSFER_ORDER)),
})
# ---------- create parser ----------
create_parser = reqparse.RequestParser()
create_parser.add_argument('date', type=str, help='单据日期')
create_parser.add_argument('draft_status', type=str, help='草稿状态', default=constant.OrderDraftStatus.PENDING)
create_parser.add_argument('from_warehouse_id', type=str, help='出货仓库')
create_parser.add_argument('to_warehouse_id', type=str, help='入货仓库')
create_parser.add_argument('notes', type=str, help='备注')
create_parser.add_argument('order_skus', action='append', type=dict, help='商品明细')
create_parser.add_argument('image_ids', type=int, help='图片id', action='append', default=[])
create_parser.add_argument('action', type=str, required=True, help='操作',
                           choices=[constant.OrderActionType.SAVE_DRAFT,
                                    constant.OrderActionType.SUBMIT])

# ---------- put parser ----------
put_parser = create_parser.copy()


class TransferOrdersResource(Resource):
    @catch_error
    @token_required
    @api.expect(create_parser)
    def post(self):
        """创建"""
        args = create_parser.parse_args()
        order_skus = args.pop('order_skus')
        image_ids = args.pop('image_ids')
        action = args.pop('action')
        args['date'] = get_default_date(args.pop('date'))

        # 创建order
        new_transfer_order = TransferOrder.create(
            **args,
            order_sn=TransferOrder.generate_order_sn_transfer(),
            commit=True
        )
        # 创建order_sku
        for order_sku_json in order_skus:
            TransferOrderSku.create(
                order_id=new_transfer_order.id,
                **order_sku_json,
            )
        # images
        if image_ids or len(image_ids) == 0:
            for image_id in image_ids:
                FileRelation.create(
                    file_id=image_id, belong_id=new_transfer_order.id,
                    belong_type=constant.FileBelongType.TRANSFER_ORDER)
        if action == constant.OrderActionType.SUBMIT:
            new_transfer_order.submit()

        db.session.commit()
        return ok(data=marshal(new_transfer_order, transfer_order_model_for_detail),
                  message='create success')

    @catch_error
    @token_required
    @api.expect(get_parser)
    def get(self):
        """获取列表"""
        args = get_parser.parse_args()
        pagination = dao.get_by_page(**args)
        # 重新获取
        new_items = []
        for ele in pagination['items']:
            transfer_order = TransferOrder.query.filter_by(id=ele['id']).first()
            new_items.append(marshal(transfer_order, transfer_order_model_for_list))
        pagination['items'] = new_items

        return ok(data=pagination,
                  message='get success')


class TransferOrderResource(Resource):
    @catch_error
    @token_required
    def get(self, obj_id):
        """获取"""
        obj = TransferOrder.query.filter_by(id=obj_id).first()
        # 手动获取 库存数量 + 成本价， 放入sku中
        for order_sku in obj.order_skus:
            # 判断单据状态 如果是草稿状态，则获取实时库存
            if obj.status == constant.OrderStatus.DRAFT:
                order_sku.from_before_num = get_sku_storage_num(order_sku.sku_id, obj.from_warehouse_id)
                order_sku.to_before_num = get_sku_storage_num(order_sku.sku_id, obj.to_warehouse_id)
        return ok(data=marshal(obj, transfer_order_model_for_detail),
                  message='get success')

    @catch_error
    @token_required
    @api.expect(put_parser)
    def put(self, obj_id):
        """更新 保存或提交"""
        args = put_parser.parse_args()
        action = args.pop('action')
        order_skus = args.pop('order_skus')
        obj = TransferOrder.query.filter_by(id=obj_id).first()

        if action == constant.OrderActionType.SAVE_DRAFT:
            obj.save_draft(order_skus, **args)
        elif action == constant.OrderActionType.SUBMIT:
            obj.save_draft(order_skus, **args)
            obj.submit()
        else:
            raise Exception("wrong action")
        return ok(data=marshal(obj, transfer_order_model_for_detail),
                  message='update success')

    @catch_error
    @token_required
    def delete(self, obj_id):
        """删除"""
        obj = TransferOrder.query.filter_by(id=obj_id).first()
        delete_id = obj.hard_delete(commit=True)
        return ok(
            data={
                'id': delete_id
            },
            message='delete success')


action_parser = reqparse.RequestParser()
action_parser.add_argument('action', type=str, required=True, help='操作',
                           choices=[constant.OrderActionType.REVOKE])


class TransferOrderActionResource(Resource):
    @catch_error
    @token_required
    def put(self, obj_id):
        """撤销"""
        args = action_parser.parse_args()
        obj = TransferOrder.query.filter_by(id=obj_id).first()
        action = args.pop('action')
        if action == constant.OrderActionType.REVOKE:
            obj.revoke()
            return ok(data=marshal(obj, transfer_order_model_for_detail),
                      message='update success')
        else:
            raise Exception("wrong action")


# --------- route ----------
api.add_resource(TransferOrdersResource, '/transfer_orders')
api.add_resource(TransferOrderResource, '/transfer_orders/<int:obj_id>')
api.add_resource(TransferOrderActionResource, '/transfer_orders/<int:obj_id>/action')  # 撤销

# 注册 response 文档
api.models[transfer_order_model_for_detail.name] = transfer_order_model_for_detail
